/* 设置坐标 */
function Point(x, y) {
    return {
        x: x,
        y: y
    }
}

/* 
    获取贝塞尔曲线的坐标
    https://www.jianshu.com/p/8f82db9556d2
    @x0, y0     标识贝塞尔曲线的起始坐标
    @x1, y1     标识贝塞尔曲线的控制点坐标
    @x2, y2     标识贝塞尔曲线的终点坐标
*/
function CubicBezier(x0, y0, x1, y1, x2, y2) {
    let t1 = 0,
        max = 1,
        PointTotal = []

    function PointOnCubicBezier1(t) {
        var tPos = [0, 0]
        tPos[0] = Math.pow((1 - t), 2) * x0 + 2 * t * (1 - t) * x1 + Math.pow(t, 2) * x2;
        tPos[1] = Math.pow((1 - t), 2) * y0 + 2 * t * (1 - t) * y1 + Math.pow(t, 2) * y2;
        return tPos;
    }
    while (t1 <= max) {
        point = PointOnCubicBezier1(t1 / max)
        t1 += 0.05;
        PointTotal.push(point)
    }
    return PointTotal
}
/* 
    获取贝塞尔曲线的坐标
    @p0, p1, p2  分别为：标识贝塞尔曲线的起始坐标、标识贝塞尔曲线的控制点坐标、标识贝塞尔曲线的终点坐标
*/
function CubicBezier2(p0, p1, p2) {
    let t1 = 0,
        max = 20,
        PointTotal = []

    function PointOnCubicBezier1(t) {
        var tPos = {}
        tPos.x = Math.pow((1 - t), 2) * p0.x + 2 * t * (1 - t) * p1.x + Math.pow(t, 2) * p2.x;
        tPos.y = Math.pow((1 - t), 2) * p0.y + 2 * t * (1 - t) * p1.y + Math.pow(t, 2) * p2.y;
        return tPos;
    }
    while (t1 <= max) {
        point = PointOnCubicBezier1(t1 / max)
        t1 += 1;
        PointTotal.push(point)
    }
    return PointTotal
}

// 画圆
function arc(x, y, r, context, color) {
    context.beginPath();
    context.arc(x, y, r, 0, 2 * Math.PI);
    if (color) context.fillStyle = color;
    else context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
    // context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
    // context.fillStyle = '#ffffff';
    context.fill();
    context.closePath();
}

// 清空画布
function clearCanvas(context) {
    context.clearRect(0, 0, formData.CanvasWeight, formData.CanvasWeight);
}


/* 
    封装方法：统计一个区间之间按照指定宽度的一连串递增的数据
    @arrData {Array} 一个数组，只能有两个值，表示从一个值到另一个值。
    @Incremental {Number} 宽度，区间会按照该宽度进行地递增
*/
function IncrementalFn(arrData, Incremental) {
    if (!Incremental || Incremental == 0) return;
    Incremental = Math.abs(Incremental)
    if (arrData[0] > arrData[1])[arrData[0], arrData[1]] = [arrData[1], arrData[0]];
    var aArr = [];
    for (let index = Number(arrData[0]); index <= Number(arrData[1]);) {
        aArr.push(index);
        index = index + Incremental;
    }
    return aArr;
}

/* 
    一个数值，按照给定长度度取出区间，最后统计区间之间按照指定宽度的一连串递增的数据
    @target {Number} 一个数值
    @Incremental {Number} 长度，根据长度截取数值的上下区间
    @Incremental2 {Number} 宽度，区间会按照该宽度进行地递增
*/
function complexData(target, Incremental, Incremental2 = 1) {
    return IncrementalFn([Number(target) - Incremental, Number(target) + Incremental], Incremental2)
}


/* 
    封装方法：设置有n个数组，每个数组中都有数据，现有需求：按照顺序从每一数组中取出一个元素，并按照取出元素的顺序添加到一个新的数组中，求有多少种组合
    ==注意==：必须要每个数组中都有数据，否则最终的返回结果是空数组。
    @doubleArrData {Array} 这是一个二维数组
*/
function combinationFn(doubleArrData) {
    var total = [];
    (function d(arr, index_ = 0, tep = []) {
        for (let index = index_; index < arr.length; index++) {
            const element = arr[index];

            if (index != 0 && tep.length !== index) continue;

            for (let index2 = 0; index2 < element.length; index2++) {
                const element2 = element[index2];

                tepClone = JSON.parse(JSON.stringify(tep));
                tepClone.push(element2);
                if (index < arr.length - 1) {
                    d(arr, index + 1, tepClone);
                } else {
                    total.push(tepClone);
                }
            }
        }
    })(doubleArrData)
    return total;
}
combinationFn2 = (array) => {
    let resultArry = [];
    array.forEach((arrItem) => {
        if (resultArry.length === 0) {
            resultArry = arrItem
        } else {
            const emptyArray = [];
            resultArry.forEach((item) => {
                arrItem.forEach((value) => {
                    emptyArray.push([item, value])
                })
            })
            resultArry = emptyArray
        }
    });
    return resultArry;
}



/* 
    计算贝塞尔曲线和直线的交点
    @lineP0, lineP1 {Point} 表示直线的两个定点
    @p0, p1, p2 {Point} 贝塞尔曲线的三个控制：p1为控制点，其他两个为开始和结束点
*/
function BesselStraightFocus(lineP0, lineP1, p0, p1, p2) {
    //根据两点式求出的直线一般式系数
    var lineA = (lineP1.y - lineP0.y);
    var lineB = (lineP0.x - lineP1.x);
    var lineC = (lineP1.x * lineP0.y - lineP1.y * lineP0.x);

    //贝塞尔曲线x分量的3个系数（可在连载十七中找到这公式）
    var ax = p0.x - 2 * p1.x + p2.x;
    var bx = 2 * p1.x - 2 * p0.x;
    var cx = p0.x;

    //贝塞尔曲线y分量的3个系数（可在连载十七中找到这公式）
    var ay = p0.y - 2 * p1.y + p2.y;
    var by = 2 * p1.y - 2 * p0.y;
    var cy = p0.y;

    //At+Bt^2+C=0
    //一元二次方程的3个系数
    var squareFormulaA = lineA * ax + lineB * ay;
    var squareFormulaB = lineA * bx + lineB * by;
    var squareFormulaC = lineA * cx + lineB * cy + lineC;
    // console.log(squareFormulaA, squareFormulaB, squareFormulaC);
    var ts = [];

    if (squareFormulaA != 0) {
        //接着求根公式
        var delta = squareFormulaB * squareFormulaB - 4 * squareFormulaA * squareFormulaC;
        // console.log(delta);
        //delta小于0时无实数解
        if (delta >= 0) {
            var t1 = (-squareFormulaB + Math.sqrt(delta)) / 2 / squareFormulaA;
            var t2 = (-squareFormulaB - Math.sqrt(delta)) / 2 / squareFormulaA;
            if (t1 >= 0 && t1 <= 1) {
                ts.push(t1);
            }
            if (t2 >= 0 && t2 <= 1) {
                ts.push(t2);
            }
        }
    } else if (squareFormulaB != 0) {
        var t = -squareFormulaC / squareFormulaB;
        if (t >= 0 && t <= 1) {
            ts.push(t);
        }

    }
    var focus = [];
    //绘制交点
    for (var i = 0, len = ts.length; i < len; i++) {
        //把t代入到参数方程中求出xy
        var t = ts[i];
        var x = ax * t * t + bx * t + cx;
        var y = ay * t * t + by * t + cy;
        // console.log(x, y);
        focus.push({
            x,
            y
        })
    }
    return focus;
}


/* 
    根据已知每条直线上的任意两点，求两条直线的交点
    @a, b 为一条直线上的两个点的坐标
    @c, d 为另一条直线上的两个点的坐标
*/
function segmentsIntr(a, b, c, d) {

    /** 1 解线性方程组, 求线段交点. **/
    // 如果分母为0 则平行或共线, 不相交  
    var denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y);
    if (denominator == 0) {
        return false;
    }

    // 线段所在直线的交点坐标 (x , y)      
    var x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) +
        (b.y - a.y) * (d.x - c.x) * a.x -
        (d.y - c.y) * (b.x - a.x) * c.x) / denominator;
    var y = -((b.y - a.y) * (d.y - c.y) * (c.x - a.x) +
        (b.x - a.x) * (d.y - c.y) * a.y -
        (d.x - c.x) * (b.y - a.y) * c.y) / denominator;

    /** 2 判断交点是否在两条线段上 **/
    // if (
    //     // 交点在线段1上  
    //     (x - a.x) * (x - b.x) <= 0 && (y - a.y) * (y - b.y) <= 0
    //     // 且交点也在线段2上  
    //     && (x - c.x) * (x - d.x) <= 0 && (y - c.y) * (y - d.y) <= 0
    // ) {
    //     // 返回交点p  
    //     return {
    //         x: x,
    //         y: y
    //     }
    // }
    return {
        x: x,
        y: y
    }
    //否则不相交  
    return false

}

/* 
    （两点式）：根据已知两点和一个x轴或y轴的值，求另一个y轴或x轴的值
    @x1, y1 第一个点
    @x2, y2 第二个点
    @x, y  连个中一个是确定值，求另一个的值
*/
function focus(x1, y1, x2, y2, x, y) {
    for (let index = 0; index < arguments.length; index++) {
        arguments[index] = Number(arguments[index])
    }
    if (x1 == x2) {
        return null;
    }
    if (y1 == y2) {
        return null;
    }

    if (!x) {
        x = (y - y1) * (x2 - x1) / (y2 - y1) + x1
    }
    if (!y) {
        y = (x - x1) * (y2 - y1) / (x2 - x1) + y1;
    }
    return [x, y]
}

/* 
    （两点式）：根据已知两点，确定直线和x轴相交的点
    @x1, y1 第一个点
    @x2, y2 第二个点
*/
function focusX(x1, y1, x2, y2, x, y) {
    for (let index = 0; index < arguments.length; index++) {
        arguments[index] = Number(arguments[index])
    }
    if (y1 == y2) {
        console.error("y轴平行了")
        return [0, 0];
    }
    // x = (y - y1) * (x2 - x1) / (y2 - y1) + x1
    x = (0 - y1) * (x2 - x1) / (y2 - y1) + x1
    return [x, 0]
}

/* 
    通过圆形角(角度)、圆心和半径，来确定弧度的交点
    @x 圆心
    @y 圆心
    @angle 斜边所对的角度
    @r 斜边长度
    @CanvasWeight 画布宽度
*/
function focusTip(x, y, r, angle) {
    for (let index = 0; index < arguments.length; index++) {
        arguments[index] = Number(arguments[index])
    }
    angle = Number(angle)
    // if (angle > 180) angle = 170
    if (angle == 0) return [x - r, y]
    if (angle == 180) return [x + r, y]
    if (angle == 90) return [x, y - r]
    if (angle == 270) return [x, y + r]

    var h = oppositeSide(angle, r) // 对边长度
    var w = adjacentSide(angle, r) // 邻边长度
    var focus;

    // if (angle < 360) {
    //     focus = [x - w, y + h];
    // } if (angle < 270) {
    //     focus = [x + w, y + h];
    // } if (angle < 180) {
    //     focus = [x + w, y - h];
    // } if (angle < 90) {
    //     focus = [x - w, y - h];
    // }

    focus = [x - w, y - h];

    return focus;
}


/* 
    通过角度和斜边长度，确认对边长度
    @angle 斜边所对的角度
    @kw 斜边长度
*/
function oppositeSide(angle, kw) {
    for (let index = 0; index < arguments.length; index++) {
        arguments[index] = Number(arguments[index])
    }
    // 度和弧度（角度和弧度）   http://c.biancheng.net/ref/62.html
    // return Math.abs(Math.sin(angle * (Math.PI / 180)) * kw)
    return Math.sin(angle * (Math.PI / 180)) * kw
}
/* 
    通过角度和斜边长度，确认邻边长度
    @angle 斜边所对的角度
    @kw 斜边长度
*/
function adjacentSide(angle, kw) {
    for (let index = 0; index < arguments.length; index++) {
        arguments[index] = Number(arguments[index])
    }
    // 度和弧度（角度和弧度）   http://c.biancheng.net/ref/62.html
    // return Math.abs(Math.cos(angle * (Math.PI / 180)) * kw)
    return Math.cos(angle * (Math.PI / 180)) * kw
}